package com.jumi.microservice.payment;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.SendResult;
import com.aliyun.openservices.ons.api.bean.ProducerBean;
import com.jumi.microservice.common.base.dto.BaseRequest;
import com.jumi.microservice.common.base.dto.BaseResponse;
import com.jumi.microservice.common.enumeration.CommonResponseEnum;
import com.jumi.microservice.common.exception.BaseException;
import com.jumi.microservice.common.utils.MD5;
import com.jumi.microservice.config.UnionPayConfig;
import com.jumi.microservice.constant.PayChannelEnum;
import com.jumi.microservice.context.UnionPayContext;
import com.jumi.microservice.dto.*;
import com.jumi.microservice.interfaces.BasePayment;
import com.jumi.microservice.interfaces.PayContext;
import com.jumi.microservice.rocketmq.RocketMqConfig;
import com.jumi.microservice.utils.UnionPayPostTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;

/**
 * @author Dirk
 * @Date 2020-08-26 16:25
 */
@Component
public class UnionPayment extends BasePayment {

    private static final Logger log = LoggerFactory.getLogger(BasePayment.class);

    @Resource
    private UnionPayConfig unionPayConfig;
    @Resource
    private UnionPayPostTemplate unionPayPostTemplate;
    @Resource
    ProducerBean producerBean;
    @Autowired
    RocketMqConfig rocketMqConfig;

    @Override
    public PayContext createContext(BaseRequest request) {
        UnionPayContext context = new UnionPayContext();
        PaymentRequest paymentRequest = (PaymentRequest) request;
        context.setOrderNo(paymentRequest.getPaymentSn());
        context.setCod(paymentRequest.getTotalAmount().toString());
        context.setOrderDesc(paymentRequest.getSubject());
        context.setPayWay(paymentRequest.getPayWay().getCode());
        return context;
    }

    @Override
    public void preProcess(PayContext context) {

    }

    @Override
    public BaseResponse coreProcess(PayContext context) {
        UnionPayContext ctx = (UnionPayContext) context;
        MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
        parameters.add("cod", ctx.getCod());
        parameters.add("mer_id", unionPayConfig.getMerId());
        parameters.add("notifyUrl", unionPayConfig.getNotifyUrl());
        parameters.add("orderDesc", ctx.getOrderDesc());
        parameters.add("order_no", ctx.getOrderNo());
        parameters.add("payway", ctx.getPayWay());
        parameters.add("qrtype", "app");
        parameters.add("subAppId", unionPayConfig.getAppId());
        JSONObject jsonObject = unionPayPostTemplate.post(unionPayConfig.getServerUrl(), parameters);
        UnionPayResponse response = new UnionPayResponse();
        response.setAppPayRequest(jsonObject.getString("appPayRequest"));
        return response;
    }

    @Override
    public void afterProcess() {

    }

    @Override
    public String getPayChannel() {
        return PayChannelEnum.UNION_PAY.name();
    }

    @Override
    public PaymentResponse refund(BaseRequest request) {
        RefundRequest refundRequest = (RefundRequest) request;
        MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
        parameters.add("mer_id", unionPayConfig.getMerId());
        parameters.add("order_no", refundRequest.getOrderSn());
        parameters.add("qrtype", "app");
        parameters.add("queryId", refundRequest.getPayNo());
        parameters.add("refund_amt", refundRequest.getAmount());
        parameters.add("refund_desc", refundRequest.getDesc());
        JSONObject jsonObject = unionPayPostTemplate.post(unionPayConfig.getRefundUrl(), parameters);
        PaymentResponse response = new PaymentResponse();
        response.setResult("SUCCESS".equals(jsonObject.getString("refundStatus")));
        return response;
    }

    @Override
    public BaseResponse completePayment(BaseRequest request) {
        PayNotifyRequest payNotifyRequest = (PayNotifyRequest) request;
        log.info("支付回调请求参数：[{}]", payNotifyRequest);
        String mac = MD5.getInstance().getMD5String(payNotifyRequest.getContext().concat(unionPayConfig.getKey()));
        if (!mac.equals(payNotifyRequest.getMac().toLowerCase())) {
            log.error("签名校验失败，本地计算：[{}], 请求参数：[{}]", mac, payNotifyRequest.getMac());
            throw new BaseException(CommonResponseEnum.SERVER_ERROR);
        }
        JSONObject jsonObject = JSON.parseObject(payNotifyRequest.getContext());
        String transType = jsonObject.getJSONObject("header").getString("transtype");
        // 支付回调和退款回调走同一路径，在此筛选出支付回调
        String paymentTransType = "P033";
        if (paymentTransType.equals(transType)) {
            log.info("UnionPay支付发送消息:[{}]", jsonObject.getString("body"));
            Message message = new Message(rocketMqConfig.getTopic(), rocketMqConfig.getTag(), "", JSON.toJSONBytes(jsonObject.getString("body")));
            SendResult sendResult = producerBean.send(message);
            log.info("UnionPay支付发送消息成功[{}],[{}]", sendResult.getMessageId(), sendResult.getTopic());
        }
        UnionPayNotifyResponse response = new UnionPayNotifyResponse();
        jsonObject.put("body", null);
        response.setContext(jsonObject.toJSONString());
        return response;
    }
}